package testadventure;

import edu.clemson.cs.hamptos.adventure.AdventureEngine;
import edu.clemson.cs.hamptos.adventure.AdventureLocation;
import edu.clemson.cs.hamptos.adventure.AdventureParser;
import edu.clemson.cs.hamptos.adventure.AdventureTarget;
import edu.clemson.cs.hamptos.adventure.AdventureWindow;
import edu.clemson.cs.hamptos.adventure.VerbStrategyAlt;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Scanner;

/**
 * <p>Acts as an interpreter for the script files passed in. Dynamically 
 * generates the adventure from scratch. Can also be seen as the overarching 
 * superclass that maintains the text adventure</p>
 * @author Nicks
 */
public class TheAdventure {
    /**
     * <p>Constructor for a new <code>TheAdventure</code> object.</p>
     * @param scriptDir - of type <code>String</code>
     * @param theParser - of type <code>AdventureParser</code>
     */
    public TheAdventure(String scriptDir, AdventureParser theParser)
    {
        initializeVerbs();
        File items = new File(scriptDir + "ScriptItems.txt");
        initializeItems(items);
        
        File exits = new File(scriptDir + "ScriptExits.txt");
        initializeExits(exits);
        
        File locations = new File(scriptDir + "ScriptLocations.txt");
        initializeLocations(locations);
        
        String titleText = "ESCAPE TEXT ADVENTURE, brought to you by the Umbrella Corporation";
        mainWindow = new AdventureWindow(titleText, startLoc, theParser);
        theEngine = mainWindow.myEngine;
    }
    
    //class variables
    public static HashMap<String, VerbStrategyAlt> verbMap = 
            new HashMap<String, VerbStrategyAlt>();
    public static HashMap<String, AdventureTarget> itemMap = 
            new HashMap<String, AdventureTarget>();
    public static HashMap<String, ItemExit> exitMap = 
            new HashMap<String, ItemExit>();
    public static HashMap<String, AdventureLocation> locationMap = 
            new HashMap<String, AdventureLocation>();
    public static AdventureWindow mainWindow;
    public static AdventureEngine theEngine;
    AdventureLocation startLoc;
    ////
    
    /**
     * <p>Initializes the <code>Items</code> <code>HashMap</code> by reading it 
     * from the script file passed in, uses BaseItem.name for the keys
     * and the actual <code>BaseItem</code> for the value</p>
     * @param inFile the script file to initialize from
     */
    private void initializeItems(File inFile)
    {
        //initialize the items from the script files
        String strItems = "";
        try
        {
            strItems = ripStringFromFile(inFile);
        }
        catch (Exception ex)
        {
            System.err.println("Could not initialize the files, "
                               + "check to make sure they are there");
            System.err.println("Error thrown: " + ex.getMessage());
        }
        Scanner itemScan = new Scanner(strItems);
        itemScan.useDelimiter("#\r\n");
        while(itemScan.hasNext())
        {
            AdventureTarget toAdd;
            StringBuilder inBlob = new StringBuilder(itemScan.next());
            String type = inBlob.substring(0, 4);
            
            if (type.equals("Item"))
            {
                inBlob.delete(0, 5);
                toAdd = new ItemFull(inBlob);
            }
            else if(type.equals("Tool"))
            {
                inBlob.delete(0, 5);
                toAdd = new ItemTool(inBlob);
            }
            else if(type.equals("Enem"))
            {
                inBlob.delete(0, 6);
                toAdd = new ItemEnemy(inBlob);
            }
            else
            {
                toAdd = new BaseItem(inBlob);
            }
            itemMap.put(toAdd.getID(), toAdd);
        }
    }
    
    /**
     * <p>Initializes the <code>locationMap</code> <code>HashMap</code> using  
     * the given script file
     * Precondition: The <code>itemMap</code> and <code>exitMap</code> <code>HashMap</code> 
     *               must be fully initialized first since this method 
     *               uses it to populate the locations
     * @param inFile 
     */
    private void initializeLocations(File inFile)
    {
        //initialize the locations from the script files
        String strItems = "";
        try
        {
            strItems = ripStringFromFile(inFile);
        }
        catch (Exception ex)
        {
            System.err.println("Could not initialize the files, "
                              + "check to make sure they are there");
            System.err.println("Error thrown: " + ex.getMessage());
        }
        
        int firstPass = 0;
        
        Scanner locScan = new Scanner(strItems);
        locScan.useDelimiter("#\r\n");
        while(locScan.hasNext())
        {
            String inBlob = locScan.next();
            BaseLocation next = new BaseLocation(inBlob, itemMap);
            locationMap.put(next.getName(), next);
            
            //sets starting location to the first entry
            if (firstPass == 0)
            {
                firstPass++;
                startLoc = next;
            }
        }
    }
    
    /**
     * <p>Rips the whole text from a file as a String, used to parse allow easy 
     * parsing of values</p>
     * @param inFile the file from which to read the text
     * @return String with the whole text absorbed
     * @throws FileNotFoundException thrown if the file does not exist
     */
    public static String ripStringFromFile(File inFile) 
             throws FileNotFoundException
    {
        int len;  
          char[] chr = new char[4096];
          StringBuilder strBuilder = new StringBuilder();
          FileReader reader = null;
          try {
              reader = new FileReader(inFile);
              while ((len = reader.read(chr)) > 0) {
                  strBuilder.append(chr, 0, len);
              }
          }
          catch (IOException ex)
          {
              //quietly suppress the exception, don't complain loudly
              System.err.println(ex.getMessage());
          }
          finally {
              try
              {
                reader.close();
              }
              catch (Exception ex)
              {
                  //quietly suppress any exceptions here, 
                  //not necessary to report
                  System.err.println(ex.getMessage());
              }
          }
          return strBuilder.toString();
    }

    /**
     * <p>Adds <code>VerbStrategyAlt</code> to the static verb 
     * <code>HashMap</code></p>
     */
    private void initializeVerbs() {
        VerbStrategyAlt vat = new VerbApplyTool();
        verbMap.put(vat.getName(), vat);
        
        VerbStrategyAlt vatc = new VerbApplyToolClose();
        verbMap.put(vatc.getName(), vatc);
        
        VerbStrategyAlt vatr = new VerbApplyToolRange();
        verbMap.put(vatr.getName(), vatr);
        
        VerbStrategyAlt vgt = new VerbGoThrough();
        verbMap.put(vgt.getName(), vgt);
        
        VerbStrategyAlt vrb = new VerbRollBody();
        verbMap.put(vrb.getName(), vrb);
        
        VerbStrategyAlt vod = new VerbOpenDrawer();
        verbMap.put(vod.getName(), vod);
        
        VerbStrategyAlt vep = new VerbEnterPassword();
        verbMap.put(vep.getName(), vep);
        
        VerbStrategyAlt vr = new VerbReload();
        verbMap.put(vr.getName(), vr);
        
        VerbStrategyAlt ve = new VerbEnter();
        verbMap.put(ve.getName(), ve);
    }

    /**
     * <p>Initializes the exitMap for use with the locations</p>
     * @param inFile 
     */
    private void initializeExits(File inFile) {
        //initialize the items and locations from the script files
        String strItems = "";
        try
        {
            strItems = ripStringFromFile(inFile);
        }
        catch (Exception ex)
        {
            System.err.println("Could not initialize the files, "
                             + "check to make sure they are there");
            System.err.println("Error thrown: " + ex.getMessage());
        }
        Scanner itemScan = new Scanner(strItems);
        itemScan.useDelimiter("#\r\n");
        while(itemScan.hasNext())
        {
            StringBuilder inBlob = new StringBuilder(itemScan.next());
            ItemExit exit = new ItemExit(inBlob);
            exitMap.put(exit.getID(), exit);
        }
    }
}
